import { get, set } from 'lodash-unified'
const is = Object.prototype.toString

export const isObject = (v: any) => is.call(v) === '[object Object]'
export const isNumber = (v: any) => is.call(v) === '[object Number]'
export const isString = (v: any) => is.call(v) === '[object String]'
export const isUndefined = (v: any) => is.call(v) === '[object Undefined]'
export const isBoolean = (v: any) => is.call(v) === '[object Boolean]'
export const isNull = (v: any) => is.call(v) === '[object Null]'
export const isArray = (v: any) => is.call(v) === '[object Array]'
export const isFunction = (v: any) => is.call(v) === '[object Function]'

/**
 * 扩展函数
 * @param sources 目标数据 数组
 * @returns
 */
export const extendSchemas = <T>(...sources: T[]): T => {
  if (sources.length < 0) {
    throw new Error('请输入至少一个参数')
  }
  if (!isObject(sources[0])) {
    throw new Error('入参必须为Object类型')
  }
  const res = sources.reduce((p, c) => Object.assign(p, c), {})
  return res as T
}

export type Arrayable<T> = T | T[]

export const getProp = <T = any>(
  obj: Record<string, any>,
  path: Arrayable<string>,
  defaultValue?: any
): { value: T } => {
  return {
    get value() {
      return get(obj, path, defaultValue)
    },
    set value(val: any) {
      set(obj, path, val)
    }
  }
}

export const getValueByPath = (object: any, prop: string) => {
  prop = prop || ''
  const paths = prop.split('.')
  let current = object
  let result = null
  for (let i = 0, j = paths.length; i < j; i++) {
    const path = paths[i]
    if (!current) break

    if (i === j - 1) {
      result = current[path]
      break
    }
    current = current[path]
  }
  return result
}

export function getPropByPath(obj: any, path: string, strict: any) {
  let tempObj = obj
  path = path.replace(/\[(\w+)\]/g, '.$1')
  path = path.replace(/^\./, '')

  const keyArr = path.split('.')
  let i = 0
  for (let len = keyArr.length; i < len - 1; ++i) {
    if (!tempObj && !strict) break
    const key = keyArr[i]
    if (key in tempObj) {
      tempObj = tempObj[key]
    } else {
      if (strict) {
        throw new Error('please transfer a valid prop path to form item!')
      }
      break
    }
  }
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : null
  }
}
